package com.itic.appbase.framework.exception;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itic.appbase.framework.plugins.logger.Log;

/**
 * 通用EXCEPTION处理.<br>
 * 通过SPRING EXCEPTION机制，统一拦截抛出的异常，并根据异常类型返回对应的内容.
 * 
 * @ClassName: SystemExceptionResolver
 * @author: djp_ivan
 * @date: Mar 31, 2015 8:43:24 AM
 * @version: V1.0
 * @Update_Comments: by djp_ivan at Mar 31, 2015 - description
 */
public class SystemExceptionResolver
        extends SimpleMappingExceptionResolver {

    private static final Logger LOGGER = Log.get(SystemExceptionResolver.class);

    /**
     * Exception 处理返回
     */
    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        // Exception对应页面，mvc conofig中配置
        String viewName = this.determineViewName(ex, request);
        // 以下通用处理，返回参数由EXCEPTION初始化确认
        return handleException(request, response, ex, viewName);
    }

    /**
     * @throws Exception
     * 
     * @param request
     * @param response
     * @param ex
     * @param viewName
     * @return
     * @throws
     */
    private ModelAndView handleException(HttpServletRequest request, HttpServletResponse response, Exception ex,
            String viewName) {
        // 判斷是否AJAX請求
        if (!isAjaxRequest(request) && null != viewName) {
            Integer statusCode = determineStatusCode(request, viewName);
            if (statusCode != null) {
                applyStatusCodeIfPossible(request, response, statusCode);
            }
            return getModelAndView(viewName, ex, request);
        } else if (isAjaxRequest(request)) {
            // AjAX
            String errorMessage = ex.getMessage();
            if (StringUtils.isEmpty(errorMessage)) {
                errorMessage = ex.getClass().getName();
            }
            LOGGER.error("Catch Exception : {}", errorMessage);
            try {
                this.responseJson(response, errorMessage);
            } catch (IOException e) {
                LOGGER.error("SystemExceptionResolver : JSON IO Exception", e);
            }
            return null;
        } else {
            return null;
        }
    }

    /**
     * @throws IOException
     * @throws JsonProcessingException
     *             response直接json返回
     * 
     * @param response
     * @param jsonObject
     * @throws Exception
     * @throws
     */
    private void responseJson(HttpServletResponse response, Object jsonObject)
            throws IOException {
        Object result = jsonObject;
        response.setContentType("application/json; charset=UTF-8");
        response.setHeader("Cache-Control", "no-cache");
        response.setCharacterEncoding("UTF-8");
        if (jsonObject instanceof String) {
            Map<String, Object> resultMap = new HashMap<String, Object>();
            resultMap.put("result", jsonObject);
            result = resultMap;
        }
        ObjectMapper mapper = new ObjectMapper();
        String jsonStr = mapper.writeValueAsString(result);
        response.getWriter().write(jsonStr);
        response.getWriter().flush();
    }

    /**
     * 判断请求类型.
     * 
     * @param request
     * @return
     * @throws
     */
    private boolean isAjaxRequest(HttpServletRequest request) {
        boolean isAjax = false;
        isAjax = request.getHeader("accept").indexOf("application/json") > -1
                || (request.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With").indexOf(
                        "XMLHttpRequest") > -1);
        return isAjax;
    }

}
